package com.zlp.service;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * https://blog.csdn.net/zhuocailing3390/article/details/124653132
 * @author ZouLiPing
 * @param
 * @date 2022/9/20 15:21
 * @return
 */
@Component
public class FileRequestServer {

    @Resource
    private RestTemplate restTemplate;

    /**
     * 默认不带头，并且请求类型为json
     *
     * @param url
     * @param method
     * @param obj
     * @param tClass 为需要返回的实体类型
     * @return
     */
    public <T> T doHttp(String url, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttp(url, MediaType.APPLICATION_JSON, null, method, obj, tClass);
    }

    /**
     * 默认不带头
     *
     * @param url
     * @param contentType
     * @param method
     * @param obj
     * @param tClass      为需要返回的实体类型
     * @return
     */
    public <T> T doHttp(String url, MediaType contentType, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttp(url, contentType, null, method, obj, tClass);
    }

    /**
     * 默认带头，并且请求类型为json
     *
     * @param url
     * @param headerMap
     * @param method
     * @param obj
     * @param tClass    为需要返回的实体类型
     * @return
     */
    public <T> T doHttp(String url, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttp(url, null, headerMap, method, obj, tClass);
    }

    /**
     * @param url
     * @param contentType
     * @param headerMap
     * @param method
     * @param obj
     * @param tClass      为需要返回的实体类型
     * @return
     */
    public <T> T doHttp(String url, MediaType contentType, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) {
        HttpHeaders headers = new HttpHeaders();
        contentType = contentType == null ? MediaType.APPLICATION_JSON : contentType;
        headers.setContentType(contentType);
        if (headerMap != null && headerMap.size() > 0) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }
        HttpEntity entity = new HttpEntity(obj, headers);
        ResponseEntity<T> exchange = restTemplate.exchange(url, method, entity, tClass);
        Class<? extends ResponseEntity> aClass = exchange.getClass();
        return exchange.getBody();
    }

    private HttpHeaders getHttpHeaders() {
        HttpHeaders headers = new HttpHeaders();
        return headers;
    }

    /**
     * 默认不带头，并且请求类型为json,返回List集合对象
     *
     * @param url
     * @param method
     * @param obj
     * @param tClass
     * @return
     */
    public <T> List<T> doHttpList(String url, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttpList(url, MediaType.APPLICATION_JSON, null, method, obj, tClass);
    }

    /**
     * 默认不带头,返回List集合对象
     *
     * @param url
     * @param contentType
     * @param method
     * @param obj
     * @param tClass      为需要返回的实体类型
     * @return
     */
    public <T> List<T> doHttpList(String url, MediaType contentType, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttpList(url, contentType, null, method, obj, tClass);
    }

    /**
     * 默认带头，并且请求类型为json,返回List集合对象
     *
     * @param url
     * @param headerMap
     * @param method
     * @param obj
     * @param tClass
     * @return
     */
    public <T> List<T> doHttpList(String url, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) {
        return doHttpList(url, null, headerMap, method, obj, tClass);
    }

    /**
     * 返回List集合对象
     *
     * @param url
     * @param contentType
     * @param headerMap
     * @param method
     * @param obj
     * @param tClass      为需要返回的实体类型
     * @param <T>
     * @return
     */
    public <T> List<T> doHttpList(String url, MediaType contentType, Map<String, String> headerMap, HttpMethod method, Object obj, Class<T> tClass) {
        HttpHeaders headers = new HttpHeaders();
        contentType = contentType == null ? MediaType.APPLICATION_JSON : contentType;
        headers.setContentType(contentType);
        if (headerMap != null && headerMap.size() > 0) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }
        HttpEntity entity = new HttpEntity(obj, headers);

        ParameterizedTypeReference<List<T>> responseType = new ParameterizedTypeReference<List<T>>() {
        };
        ResponseEntity<List<T>> exchange = restTemplate.exchange(url, method, entity, responseType);
        // RestTemplate 会将List<obj>转为List<LinkedHashMap>
        List<T> list = exchange.getBody();
        return mapToEntity(list, tClass);
    }


    public static <T> List<T> mapToEntity(List<T> body, Class<T> clazz) {
        List<T> list = new ArrayList<>();
        if (body.size() <= 0) {
            return list;
        }

        List<Map<String, Object>> mapList = new ArrayList<>();
        for (T t : body) {
            Map<String, Object> map = (Map<String, Object>) t;
            mapList.add(map);
        }

        try {

            Field[] declaredFields = clazz.getDeclaredFields();
            for (Map<String, Object> map : mapList) {
                T t = clazz.newInstance();
                for (Field declaredField : declaredFields) {
                    declaredField.setAccessible(true);
                    String name = declaredField.getName();
                    if (null != map.get(name)) {
                        declaredField.set(t, map.get(name));
                    }
                }
                list.add(t);
            }
        } catch (Exception e) {
            throw new RuntimeException("属性设置失败！");
        }
        return list;
    }
}
